"""
简化的帧处理器
Simplified Frame Processor

提供视频帧的AI处理和分析功能：
- 帧数据预处理
- AI算法集成接口
- 批量处理支持
- 结果格式化和输出
"""
import asyncio
import logging
import time
from typing import Dict, List, Optional, Callable, Any, Tuple
from datetime import datetime
from dataclasses import dataclass
from enum import Enum
import cv2
import numpy as np
from concurrent.futures import ThreadPoolExecutor

from config.settings import settings

logger = logging.getLogger(__name__)


class ProcessingMode(str, Enum):
    """处理模式"""
    REAL_TIME = "real_time"  # 实时处理
    BATCH = "batch"  # 批量处理
    ON_DEMAND = "on_demand"  # 按需处理


@dataclass
class ProcessingResult:
    """处理结果"""
    camera_id: str
    frame_number: int
    timestamp: datetime
    processing_time: float
    results: Dict[str, Any]
    success: bool
    error_message: Optional[str] = None


class FrameProcessor:
    """简化的帧处理器"""
    
    def __init__(self, max_workers: int = None):
        self.max_workers = max_workers or settings.AI_PROCESSING_WORKERS
        self.thread_pool = ThreadPoolExecutor(max_workers=self.max_workers)
        
        # AI服务注册表
        self.ai_services: Dict[str, Callable] = {}
        
        # 处理队列
        self.processing_queue: asyncio.Queue = asyncio.Queue(maxsize=100)
        self.result_queue: asyncio.Queue = asyncio.Queue(maxsize=100)
        
        # 处理任务
        self.processing_task: Optional[asyncio.Task] = None
        self.is_running = False
        
        # 统计信息
        self.stats = {
            "frames_processed": 0,
            "frames_failed": 0,
            "total_processing_time": 0.0,
            "average_processing_time": 0.0,
            "queue_size": 0
        }
    
    def register_ai_service(self, service_name: str, service_func: Callable[[np.ndarray], Dict[str, Any]]):
        """注册AI服务"""
        self.ai_services[service_name] = service_func
        logger.info(f"注册AI服务: {service_name}")
    
    def unregister_ai_service(self, service_name: str):
        """注销AI服务"""
        if service_name in self.ai_services:
            del self.ai_services[service_name]
            logger.info(f"注销AI服务: {service_name}")
    
    async def start_processing(self):
        """启动处理任务"""
        if self.is_running:
            logger.warning("帧处理器已在运行")
            return
        
        self.is_running = True
        self.processing_task = asyncio.create_task(self._processing_loop())
        logger.info("帧处理器启动")
    
    async def stop_processing(self):
        """停止处理任务"""
        if not self.is_running:
            return
        
        self.is_running = False
        
        if self.processing_task:
            self.processing_task.cancel()
            try:
                await self.processing_task
            except asyncio.CancelledError:
                pass
        
        logger.info("帧处理器停止")
    
    async def _processing_loop(self):
        """处理循环"""
        while self.is_running:
            try:
                # 从队列获取处理任务
                task_data = await asyncio.wait_for(
                    self.processing_queue.get(), 
                    timeout=1.0
                )
                
                # 处理帧
                result = await self._process_frame_task(task_data)
                
                # 将结果放入结果队列
                try:
                    await asyncio.wait_for(
                        self.result_queue.put(result),
                        timeout=0.1
                    )
                except asyncio.TimeoutError:
                    logger.warning("结果队列已满，丢弃处理结果")
                
                # 更新统计
                self._update_stats(result)
                
            except asyncio.TimeoutError:
                continue
            except Exception as e:
                logger.error(f"处理循环异常: {e}")
    
    async def _process_frame_task(self, task_data: Dict[str, Any]) -> ProcessingResult:
        """处理单个帧任务"""
        start_time = time.time()
        
        try:
            frame_data = task_data["frame_data"]
            ai_services = task_data["ai_services"]
            
            results = {}
            
            # 执行AI服务处理
            for service_name in ai_services:
                if service_name in self.ai_services:
                    service_func = self.ai_services[service_name]
                    
                    # 在线程池中执行AI处理
                    loop = asyncio.get_event_loop()
                    service_result = await loop.run_in_executor(
                        self.thread_pool,
                        service_func,
                        frame_data.frame
                    )
                    
                    results[service_name] = service_result
                else:
                    logger.warning(f"AI服务不存在: {service_name}")
                    results[service_name] = {"error": "服务不存在"}
            
            processing_time = time.time() - start_time
            
            return ProcessingResult(
                camera_id=frame_data.camera_id,
                frame_number=frame_data.frame_number,
                timestamp=frame_data.timestamp,
                processing_time=processing_time,
                results=results,
                success=True
            )
            
        except Exception as e:
            processing_time = time.time() - start_time
            logger.error(f"处理帧任务异常: {e}")
            
            return ProcessingResult(
                camera_id=task_data.get("frame_data", {}).get("camera_id", "unknown"),
                frame_number=task_data.get("frame_data", {}).get("frame_number", 0),
                timestamp=datetime.now(),
                processing_time=processing_time,
                results={},
                success=False,
                error_message=str(e)
            )
    
    async def process_frame_async(self, frame_data, ai_services: List[str]) -> bool:
        """异步处理帧"""
        try:
            task_data = {
                "frame_data": frame_data,
                "ai_services": ai_services
            }
            
            await asyncio.wait_for(
                self.processing_queue.put(task_data),
                timeout=0.1
            )
            
            self.stats["queue_size"] = self.processing_queue.qsize()
            return True
            
        except asyncio.TimeoutError:
            logger.warning("处理队列已满")
            return False
        except Exception as e:
            logger.error(f"异步处理帧异常: {e}")
            return False
    
    async def process_frame_sync(self, frame_data, ai_services: List[str]) -> ProcessingResult:
        """同步处理帧"""
        task_data = {
            "frame_data": frame_data,
            "ai_services": ai_services
        }
        
        result = await self._process_frame_task(task_data)
        self._update_stats(result)
        return result
    
    async def get_processing_result(self, timeout: float = 1.0) -> Optional[ProcessingResult]:
        """获取处理结果"""
        try:
            result = await asyncio.wait_for(
                self.result_queue.get(),
                timeout=timeout
            )
            return result
        except asyncio.TimeoutError:
            return None
        except Exception as e:
            logger.error(f"获取处理结果异常: {e}")
            return None
    
    def _update_stats(self, result: ProcessingResult):
        """更新统计信息"""
        if result.success:
            self.stats["frames_processed"] += 1
        else:
            self.stats["frames_failed"] += 1
        
        self.stats["total_processing_time"] += result.processing_time
        
        total_frames = self.stats["frames_processed"] + self.stats["frames_failed"]
        if total_frames > 0:
            self.stats["average_processing_time"] = (
                self.stats["total_processing_time"] / total_frames
            )
    
    def preprocess_frame(self, frame: np.ndarray, target_size: Tuple[int, int] = None) -> np.ndarray:
        """预处理帧数据"""
        try:
            # 调整大小
            if target_size:
                frame = cv2.resize(frame, target_size)
            
            # 可以添加其他预处理步骤
            # 如：去噪、增强对比度等
            
            return frame
            
        except Exception as e:
            logger.error(f"预处理帧异常: {e}")
            return frame
    
    def postprocess_results(self, results: Dict[str, Any]) -> Dict[str, Any]:
        """后处理结果"""
        try:
            # 可以添加结果后处理逻辑
            # 如：结果融合、置信度过滤等
            
            processed_results = {}
            
            for service_name, result in results.items():
                if isinstance(result, dict) and "error" not in result:
                    # 添加置信度阈值过滤
                    confidence = result.get("confidence", 1.0)
                    if confidence >= 0.5:  # 可配置的置信度阈值
                        processed_results[service_name] = result
                    else:
                        processed_results[service_name] = {
                            "status": "low_confidence",
                            "confidence": confidence
                        }
                else:
                    processed_results[service_name] = result
            
            return processed_results
            
        except Exception as e:
            logger.error(f"后处理结果异常: {e}")
            return results
    
    def get_statistics(self) -> Dict[str, Any]:
        """获取统计信息"""
        return {
            **self.stats,
            "registered_services": list(self.ai_services.keys()),
            "is_running": self.is_running,
            "queue_sizes": {
                "processing": self.processing_queue.qsize(),
                "result": self.result_queue.qsize()
            }
        }
    
    async def cleanup(self):
        """清理资源"""
        await self.stop_processing()
        self.thread_pool.shutdown(wait=True)
        logger.info("帧处理器资源清理完成")


class BasicImageProcessors:
    """基础图像处理器集合"""
    
    @staticmethod
    def motion_detection(frame: np.ndarray, background: Optional[np.ndarray] = None) -> Dict[str, Any]:
        """运动检测"""
        try:
            gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
            
            if background is None:
                return {"motion_detected": False, "motion_area": 0}
            
            # 计算差异
            diff = cv2.absdiff(gray, background)
            
            # 阈值处理
            _, thresh = cv2.threshold(diff, 30, 255, cv2.THRESH_BINARY)
            
            # 形态学操作
            kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5))
            thresh = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel)
            
            # 计算运动区域
            motion_area = cv2.countNonZero(thresh)
            motion_detected = motion_area > 1000  # 阈值可配置
            
            return {
                "motion_detected": motion_detected,
                "motion_area": int(motion_area),
                "confidence": min(motion_area / 10000, 1.0)
            }
            
        except Exception as e:
            return {"error": str(e)}
    
    @staticmethod
    def brightness_analysis(frame: np.ndarray) -> Dict[str, Any]:
        """亮度分析"""
        try:
            gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
            
            # 计算亮度统计
            mean_brightness = np.mean(gray)
            std_brightness = np.std(gray)
            
            # 亮度等级判断
            if mean_brightness < 50:
                brightness_level = "dark"
            elif mean_brightness < 150:
                brightness_level = "normal"
            else:
                brightness_level = "bright"
            
            return {
                "mean_brightness": float(mean_brightness),
                "std_brightness": float(std_brightness),
                "brightness_level": brightness_level,
                "confidence": 1.0
            }
            
        except Exception as e:
            return {"error": str(e)}
    
    @staticmethod
    def edge_detection(frame: np.ndarray) -> Dict[str, Any]:
        """边缘检测"""
        try:
            gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
            
            # Canny边缘检测
            edges = cv2.Canny(gray, 100, 200)
            
            # 计算边缘密度
            edge_pixels = cv2.countNonZero(edges)
            total_pixels = edges.shape[0] * edges.shape[1]
            edge_density = edge_pixels / total_pixels
            
            return {
                "edge_pixels": int(edge_pixels),
                "edge_density": float(edge_density),
                "has_strong_edges": edge_density > 0.05,
                "confidence": 1.0
            }
            
        except Exception as e:
            return {"error": str(e)}
    
    @staticmethod
    def color_analysis(frame: np.ndarray) -> Dict[str, Any]:
        """颜色分析"""
        try:
            # 计算颜色直方图
            hist_b = cv2.calcHist([frame], [0], None, [256], [0, 256])
            hist_g = cv2.calcHist([frame], [1], None, [256], [0, 256])
            hist_r = cv2.calcHist([frame], [2], None, [256], [0, 256])
            
            # 计算主要颜色
            mean_b = np.mean(frame[:, :, 0])
            mean_g = np.mean(frame[:, :, 1])
            mean_r = np.mean(frame[:, :, 2])
            
            return {
                "mean_colors": {
                    "blue": float(mean_b),
                    "green": float(mean_g),
                    "red": float(mean_r)
                },
                "dominant_color": "blue" if mean_b > max(mean_g, mean_r) else 
                                 "green" if mean_g > mean_r else "red",
                "confidence": 1.0
            }
            
        except Exception as e:
            return {"error": str(e)}


# 全局帧处理器实例
_frame_processor: Optional[FrameProcessor] = None


def get_frame_processor() -> FrameProcessor:
    """获取帧处理器实例"""
    global _frame_processor
    if _frame_processor is None:
        _frame_processor = FrameProcessor()
        
        # 注册基础处理器
        _frame_processor.register_ai_service("motion_detection", BasicImageProcessors.motion_detection)
        _frame_processor.register_ai_service("brightness_analysis", BasicImageProcessors.brightness_analysis)
        _frame_processor.register_ai_service("edge_detection", BasicImageProcessors.edge_detection)
        _frame_processor.register_ai_service("color_analysis", BasicImageProcessors.color_analysis)
        
    return _frame_processor